﻿/* 
* Copyright (c) 2010, The University of Texas at Austin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, 
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, 
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, 
* this list of conditions and the following disclaimer in the documentation and/or other materials 
* provided with the distribution.
*
* Neither the name of The University of Texas at Austin nor the names of its contributors may be 
* used to endorse or promote products derived from this software without specific prior written 
* permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

using System;
using System.Text;
using System.Xml.Linq;
using Bio.Data;
using Bio.Data.Interfaces;
using Bio.Data.Providers.Structure;
using Bio.Views.Structure.Editor.Internal.Data;

namespace Bio.Views.Structure.Editor.Internal.Algorithms
{
    public class ExportDiagramToRNAml
    {
        public static void ExportDiagram(StructureModelData diagram, string targetFile)
        {
            if (diagram == null ||
                diagram.Entity == null ||
                diagram.Entity.Sequence == null ||
                diagram.Entity.BasePairs == null)
                throw new ArgumentException("Structure model incomplete or empty");

            XElement diagramOutput = new XElement(RNAMLTags.RNAMLLabel);
            diagramOutput.Add(new XAttribute(RNAMLTags.RNAMLVersionLabel, "1.1"));

            XElement molecule = new XElement(RNAMLTags.RNAMLMoleculeLabel);

            molecule.Add(new XAttribute(RNAMLTags.RNAMLMoleculeIDAttribute, "Unknown")); //In the future, we may want to prompt for an id
            diagramOutput.Add(molecule);

            XElement identity = new XElement(RNAMLTags.RNAMLIdentityLabel);
            if (!string.IsNullOrEmpty(diagram.ScientificName))
                identity.Add(new XElement(RNAMLTags.RNAMLIdentityNameLabel, diagram.ScientificName));
            else
                identity.Add(new XElement(RNAMLTags.RNAMLIdentityNameLabel, "Unknown")); //In the future, we may want to promot for a name or create a link to an alignment for a diagram that is not coming from rCAD.

            molecule.Add(identity);

            XElement sequence = new XElement(RNAMLTags.RNAMLSequenceLabel);
            StringBuilder sequenceString = new StringBuilder();
            foreach (var nt in diagram.Entity.Sequence.SequenceData)
                sequenceString.Append(nt.Value);
            sequence.Add(new XElement(RNAMLTags.RNAMLSequenceDataLabel, sequenceString.ToString()));

            molecule.Add(sequence);

            XElement structure = new XElement(RNAMLTags.RNAMLStructureLabel);
            XElement structuremodel = new XElement(RNAMLTags.RNAMLStructureModelLabel);
            structure.Add(structuremodel);

            StructureModelMetadata structureModelMetadata = null;
            if (diagram.Entity.StructureModelPropertyEdits != null)
                structureModelMetadata = diagram.Entity.StructureModelPropertyEdits;
            else
            {
                structureModelMetadata = diagram.Entity.StructureModelProperties;
            }

            if (structureModelMetadata != null && structureModelMetadata.NucleotideRenderingMode.HasValue)
            {
                XComment smNtStyle = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideRenderingStyleLabel, structureModelMetadata.NucleotideRenderingMode));
                structuremodel.Add(smNtStyle);
            }

            if (structureModelMetadata != null && structureModelMetadata.NucleotideTextRendering != null)
            {
                if (structureModelMetadata.NucleotideTextRendering.Font != null)
                {
                    XComment smNtFont = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFontLabel, structureModelMetadata.NucleotideTextRendering.Font));
                    structuremodel.Add(smNtFont);
                }

                if (structureModelMetadata.NucleotideTextRendering.Color != null)
                {
                    XComment smNtColor = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFillLabel, structureModelMetadata.NucleotideTextRendering.Color));
                    structuremodel.Add(smNtColor);
                }

                if (structureModelMetadata.NucleotideTextRendering.FontStyle != null)
                {
                    XComment smNtFontStyle = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFontStyleLabel, structureModelMetadata.NucleotideTextRendering.FontStyle));
                    structuremodel.Add(smNtFontStyle);
                }

                if (structureModelMetadata.NucleotideTextRendering.FontWeight != null)
                {
                    XComment smNtFontWeight = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFontWeightLabel, structureModelMetadata.NucleotideTextRendering.FontWeight));
                    structuremodel.Add(smNtFontWeight);
                }

                if (structureModelMetadata.NucleotideTextRendering.FontSize > 0.0)
                {
                    XComment smNtFontSize = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFontSizeLabel, structureModelMetadata.NucleotideTextRendering.FontSize));
                    structuremodel.Add(smNtFontSize);
                }
            }

            if (structureModelMetadata != null && structureModelMetadata.NucleotideCircleRendering != null)
            {
                if (structureModelMetadata.NucleotideCircleRendering.Diameter > 0.0)
                {
                    XComment smNtCircleDiameter = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleDiameterLabel, structureModelMetadata.NucleotideCircleRendering.Diameter));
                    structuremodel.Add(smNtCircleDiameter);
                }

                if (structureModelMetadata.NucleotideCircleRendering.EdgeThickness > 0.0)
                {
                    XComment smNtCircleEdgeThickness = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleEdgeThicknessLabel, structureModelMetadata.NucleotideCircleRendering.EdgeThickness));
                    structuremodel.Add(smNtCircleEdgeThickness);
                }

                if (structureModelMetadata.NucleotideCircleRendering.Filled.HasValue)
                {
                    XComment smNtCircleFilled = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleFilledLabel, structureModelMetadata.NucleotideCircleRendering.Filled));
                    structuremodel.Add(smNtCircleFilled);
                }

                if (structureModelMetadata.NucleotideCircleRendering.EdgeColor != null)
                {
                    XComment smNtCircleEdgeColor = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleEdgeFillLabel, structureModelMetadata.NucleotideCircleRendering.EdgeColor));
                    structuremodel.Add(smNtCircleEdgeColor);
                }

                if (structureModelMetadata.NucleotideCircleRendering.FillColor != null)
                {
                    XComment smNtCircleFillColor = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleFillLabel, structureModelMetadata.NucleotideCircleRendering.FillColor));
                    structuremodel.Add(smNtCircleFillColor);
                }
            }

            if (structureModelMetadata != null && structureModelMetadata.ConnectorStyle.HasValue)
            {
                XComment smBPConnStyle = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorRenderingStyleLabel, structureModelMetadata.ConnectorStyle.Value));
                structuremodel.Add(smBPConnStyle);
            }

            if (structureModelMetadata != null && structureModelMetadata.ConnectorVisible.HasValue)
            {
                XComment smBPConnVisible = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorVisibleLabel, structureModelMetadata.ConnectorVisible.Value));
                structuremodel.Add(smBPConnVisible);
            }

            if (structureModelMetadata != null && structureModelMetadata.ConnectorRendering != null)
            {
                if (structureModelMetadata.ConnectorRendering.Size > 0.0)
                {
                    XComment smBPConnSize = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorSizeLabel, structureModelMetadata.ConnectorRendering.Size));
                    structuremodel.Add(smBPConnSize);
                }

                if (structureModelMetadata.ConnectorRendering.EdgeThickness > 0.0)
                {
                    XComment smBPConnThickness = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorStrokeThicknessLabel, structureModelMetadata.ConnectorRendering.EdgeThickness));
                    structuremodel.Add(smBPConnThickness);
                }

                if (structureModelMetadata.ConnectorRendering.Filled.HasValue)
                {
                    XComment smBPConnFilled = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorFilledLabel, structureModelMetadata.ConnectorRendering.Filled));
                    structuremodel.Add(smBPConnFilled);
                }

                if (structureModelMetadata.ConnectorRendering.FillColor != null)
                {
                    XComment smBPConnFill = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorFillColorLabel, structureModelMetadata.ConnectorRendering.FillColor));
                    structuremodel.Add(smBPConnFill);
                }

                if (structureModelMetadata.ConnectorRendering.StrokeColor != null)
                {
                    XComment smBPConnStroke = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorStrokeColorLabel, structureModelMetadata.ConnectorRendering.StrokeColor));
                    structuremodel.Add(smBPConnStroke);
                }
            }
            
            XElement structureannotation = new XElement(RNAMLTags.RNAMLStructureModelAnnotationLabel);
            foreach (var basePair in diagram.Entity.BasePairs)
            {
                XElement smBPLabel = new XElement(RNAMLTags.RNAMLBasePairLabel);
                IExtensibleProperties bpProps = basePair as IExtensibleProperties;
                if (bpProps != null)
                {
                    BasePairMetadata bpMetadata = null;
                    if(diagram.Entity.BasePairPropertyEdits.ContainsKey(basePair.FivePrimeIndex)) //We pickup the edits instead of the actual data object
                    {
                        bpMetadata = diagram.Entity.BasePairPropertyEdits[basePair.FivePrimeIndex];
                    }
                    else
                    {
                        if(bpProps.DoesExtendedPropertyExist(BasePairMetadata.Key))
                            bpMetadata = bpProps.GetExtendedProperty<BasePairMetadata>(BasePairMetadata.Key);
                    }
                    
                    if (bpMetadata != null)
                    {
                        if (bpMetadata.ConnectorVisible.HasValue)
                        {
                            XComment bpVis = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorVisibleLabel, bpMetadata.ConnectorVisible));
                            smBPLabel.Add(bpVis);
                        }

                        if (bpMetadata.ConnectorStyle.HasValue)
                        {
                            XComment bpConnRenderingStyle = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorRenderingStyleLabel, bpMetadata.ConnectorStyle));
                            smBPLabel.Add(bpConnRenderingStyle);
                        }

                        if (bpMetadata.ConnectorRendering != null)
                        {
                            if (bpMetadata.ConnectorRendering.FillColor != null)
                            {
                                XComment bpConnFillColor = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorFillColorLabel, bpMetadata.ConnectorRendering.FillColor));
                                smBPLabel.Add(bpConnFillColor);
                            }

                            if (bpMetadata.ConnectorRendering.StrokeColor != null)
                            {
                                XComment bpConnStrokeColor = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorStrokeColorLabel, bpMetadata.ConnectorRendering.StrokeColor));
                                smBPLabel.Add(bpConnStrokeColor);
                            }

                            if (bpMetadata.ConnectorRendering.Size > 0.0)
                            {
                                XComment bpConnSize = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorSizeLabel, bpMetadata.ConnectorRendering.Size));
                                smBPLabel.Add(bpConnSize);
                            }

                            if (bpMetadata.ConnectorRendering.EdgeThickness > 0.0)
                            {
                                XComment bpConnEdgeThickness = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorStrokeThicknessLabel, bpMetadata.ConnectorRendering.EdgeThickness));
                                smBPLabel.Add(bpConnEdgeThickness);
                            }

                            if (bpMetadata.ConnectorRendering.Filled.HasValue)
                            {
                                XComment bpConnFilled = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelPairConnectorFilledLabel, bpMetadata.ConnectorRendering.Filled));
                                smBPLabel.Add(bpConnFilled);
                            }
                        }

                        if (bpMetadata.NucleotideRenderingProperties != null)
                        {
                            if (bpMetadata.NucleotideRenderingProperties.TextRendering != null)
                            {
                                if (bpMetadata.NucleotideRenderingProperties.TextRendering.Font != null)
                                {
                                    XComment ntFont = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFontLabel, bpMetadata.NucleotideRenderingProperties.TextRendering.Font));
                                    smBPLabel.Add(ntFont);
                                }

                                if (bpMetadata.NucleotideRenderingProperties.TextRendering.Color != null)
                                {
                                    XComment ntColor = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFillLabel, bpMetadata.NucleotideRenderingProperties.TextRendering.Color));
                                    smBPLabel.Add(ntColor);
                                }

                                if (bpMetadata.NucleotideRenderingProperties.TextRendering.FontStyle != null)
                                {
                                    XComment ntFontStyle = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFontStyleLabel, bpMetadata.NucleotideRenderingProperties.TextRendering.FontStyle));
                                    smBPLabel.Add(ntFontStyle);
                                }

                                if (bpMetadata.NucleotideRenderingProperties.TextRendering.FontWeight != null)
                                {
                                    XComment ntFontWeight = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFontWeightLabel, bpMetadata.NucleotideRenderingProperties.TextRendering.FontWeight));
                                    smBPLabel.Add(ntFontWeight);
                                }

                                if (bpMetadata.NucleotideRenderingProperties.TextRendering.FontSize > 0.0)
                                {
                                    XComment ntFontSize = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFontSizeLabel, bpMetadata.NucleotideRenderingProperties.TextRendering.FontSize));
                                    smBPLabel.Add(ntFontSize);
                                }
                            }

                            if (bpMetadata.NucleotideRenderingProperties.CircleRendering != null)
                            {
                                if (bpMetadata.NucleotideRenderingProperties.CircleRendering.Filled.HasValue)
                                {
                                    XComment ntCircleRenderingFilled = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleFilledLabel, bpMetadata.NucleotideRenderingProperties.CircleRendering.Filled));
                                    smBPLabel.Add(ntCircleRenderingFilled);
                                }

                                if (bpMetadata.NucleotideRenderingProperties.CircleRendering.Diameter > 0.0)
                                {
                                    XComment ntCircleRenderingDiameter = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleDiameterLabel, bpMetadata.NucleotideRenderingProperties.CircleRendering.Diameter));
                                    smBPLabel.Add(ntCircleRenderingDiameter);
                                }

                                if (bpMetadata.NucleotideRenderingProperties.CircleRendering.EdgeThickness > 0.0)
                                {
                                    XComment ntCircleRenderingEdgeThickness = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleEdgeThicknessLabel, bpMetadata.NucleotideRenderingProperties.CircleRendering.EdgeThickness));
                                    smBPLabel.Add(ntCircleRenderingEdgeThickness);
                                }

                                if (bpMetadata.NucleotideRenderingProperties.CircleRendering.EdgeColor != null)
                                {
                                    XComment ntCircleRenderingEdgeColor = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleEdgeFillLabel, bpMetadata.NucleotideRenderingProperties.CircleRendering.EdgeColor));
                                    smBPLabel.Add(ntCircleRenderingEdgeColor);
                                }

                                if (bpMetadata.NucleotideRenderingProperties.CircleRendering.FillColor != null)
                                {
                                    XComment ntCircleRenderingFillColor = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleFillLabel, bpMetadata.NucleotideRenderingProperties.CircleRendering.FillColor));
                                    smBPLabel.Add(ntCircleRenderingFillColor);
                                }
                            }

                            if (bpMetadata.NucleotideRenderingProperties.Visible.HasValue)
                            {
                                XComment ntVis = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideVisibilityLabel, bpMetadata.NucleotideRenderingProperties.Visible));
                                smBPLabel.Add(ntVis);
                            }

                            if (bpMetadata.NucleotideRenderingProperties.Style.HasValue)
                            {
                                XComment ntStyle = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideRenderingStyleLabel, bpMetadata.NucleotideRenderingProperties.Style));
                                smBPLabel.Add(ntStyle);
                            }

                            if (bpMetadata.NucleotideRenderingProperties.IsSubstituted)
                            {
                                XComment ntSub = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideSubstitutionLabel, bpMetadata.NucleotideRenderingProperties.SubstitutionCharacter));
                                smBPLabel.Add(ntSub);
                            }
                        }
                    }
                }

                smBPLabel.Add(new XElement(RNAMLTags.RNAMLBasePairFivePrimeLabel,
                                new XElement(RNAMLTags.RNAMLBaseIDLabel,
                                  new XElement(RNAMLTags.RNAMLBasePositionLabel, (basePair.FivePrimeIndex + 1)))));
                smBPLabel.Add(new XElement(RNAMLTags.RNAMLBasePairThreePrimeLabel,
                                new XElement(RNAMLTags.RNAMLBaseIDLabel,
                                  new XElement(RNAMLTags.RNAMLBasePositionLabel, (basePair.ThreePrimeIndex + 1)))));
                structureannotation.Add(smBPLabel);
            }
            structuremodel.Add(structureannotation);

            IExtensibleProperties seqProps = diagram.Entity.Sequence as IExtensibleProperties;
            if (seqProps != null && seqProps.DoesExtendedPropertyExist(SequenceMetadata.Key))
            {
                SequenceMetadata seqMetadata = seqProps.GetExtendedProperty<SequenceMetadata>(SequenceMetadata.Key);
                SequenceRendering rendering = null;
                if (diagram.Entity.SequenceRenderingEdits != null)
                {
                    rendering = diagram.Entity.SequenceRenderingEdits;
                }
                else
                {
                    if (seqMetadata.Data.ContainsKey(SequenceRendering.Key))
                    {
                        rendering = seqMetadata.Data[SequenceRendering.Key] as SequenceRendering;
                    }
                }

                if (rendering != null && rendering.RenderingMap.Count == diagram.Entity.Sequence.SequenceData.Count)
                {
                    XElement structuredisplay = new XElement(RNAMLTags.RNAMLStructureModelDisplayLabel);
                    foreach (var ntIdx in rendering.RenderingMap.Keys)
                    {
                        XElement smDisplayPosLabel = new XElement(RNAMLTags.RNAMLStructureModelDisplayPositionLabel);
                        XElement smDisplayBaseIDLabel = new XElement(RNAMLTags.RNAMLBaseIDLabel);
                        smDisplayPosLabel.Add(smDisplayBaseIDLabel);

                        IExtensibleProperties ntProps = diagram.Entity.Sequence.SequenceData[ntIdx] as IExtensibleProperties;
                        if(ntProps != null)
                        {
                            NucleotideMetadata ntMetadata = null;
                            if (diagram.Entity.NucleotidePropertyEdits.ContainsKey(ntIdx))
                            {
                                ntMetadata = diagram.Entity.NucleotidePropertyEdits[ntIdx];
                            }
                            else
                            {
                                if (ntProps.DoesExtendedPropertyExist(NucleotideMetadata.Key))
                                    ntMetadata = ntProps.GetExtendedProperty<NucleotideMetadata>(NucleotideMetadata.Key);
                            }

                            if(ntMetadata != null)
                            {
                                if (ntMetadata.TextRendering != null)
                                {
                                    if (ntMetadata.TextRendering.Font != null)
                                    {
                                        XComment ntFont = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFontLabel, ntMetadata.TextRendering.Font));
                                        smDisplayBaseIDLabel.Add(ntFont);
                                    }

                                    if (ntMetadata.TextRendering.Color != null)
                                    {
                                        XComment ntColor = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFillLabel, ntMetadata.TextRendering.Color));
                                        smDisplayBaseIDLabel.Add(ntColor);
                                    }

                                    if (ntMetadata.TextRendering.FontStyle != null)
                                    {
                                        XComment ntFontStyle = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFontStyleLabel, ntMetadata.TextRendering.FontStyle));
                                        smDisplayBaseIDLabel.Add(ntFontStyle);
                                    }

                                    if (ntMetadata.TextRendering.FontWeight != null)
                                    {
                                        XComment ntFontWeight = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFontWeightLabel, ntMetadata.TextRendering.FontWeight));
                                        smDisplayBaseIDLabel.Add(ntFontWeight);
                                    }

                                    if (ntMetadata.TextRendering.FontSize > 0.0)
                                    {
                                        XComment ntFontSize = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideFontSizeLabel, ntMetadata.TextRendering.FontSize));
                                        smDisplayBaseIDLabel.Add(ntFontSize);
                                    }
                                }
                                  
                                if(ntMetadata.CircleRendering != null)
                                {
                                    if (ntMetadata.CircleRendering.Filled.HasValue)
                                    {
                                        XComment ntCircleRenderingFilled = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleFilledLabel, ntMetadata.CircleRendering.Filled));
                                        smDisplayBaseIDLabel.Add(ntCircleRenderingFilled);
                                    }

                                    if (ntMetadata.CircleRendering.Diameter > 0.0)
                                    {
                                        XComment ntCircleRenderingDiameter = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleDiameterLabel, ntMetadata.CircleRendering.Diameter));
                                        smDisplayBaseIDLabel.Add(ntCircleRenderingDiameter);
                                    }

                                    if (ntMetadata.CircleRendering.EdgeThickness > 0.0)
                                    {
                                        XComment ntCircleRenderingEdgeThickness = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleEdgeThicknessLabel, ntMetadata.CircleRendering.EdgeThickness));
                                        smDisplayBaseIDLabel.Add(ntCircleRenderingEdgeThickness);
                                    }

                                    if (ntMetadata.CircleRendering.EdgeColor != null)
                                    {
                                        XComment ntCircleRenderingEdgeColor = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleEdgeFillLabel, ntMetadata.CircleRendering.EdgeColor));
                                        smDisplayBaseIDLabel.Add(ntCircleRenderingEdgeColor);
                                    }

                                    if (ntMetadata.CircleRendering.FillColor != null)
                                    {
                                        XComment ntCircleRenderingFillColor = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideCircleFillLabel, ntMetadata.CircleRendering.FillColor));
                                        smDisplayBaseIDLabel.Add(ntCircleRenderingFillColor);
                                    }
                                }

                                if (ntMetadata.Visible.HasValue)
                                {
                                    XComment ntVis = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideVisibilityLabel, ntMetadata.Visible));
                                    smDisplayBaseIDLabel.Add(ntVis);        
                                }

                                if (ntMetadata.Style.HasValue)
                                {
                                    XComment ntStyle = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideRenderingStyleLabel, ntMetadata.Style));
                                    smDisplayBaseIDLabel.Add(ntStyle);
                                }

                                if (ntMetadata.IsSubstituted)
                                {
                                    XComment ntSub = new XComment(string.Format(RNAMLTags.StrMLExtensionFormat, RNAStructureModelXMLTags.StructureModelNucleotideSubstitutionLabel, ntMetadata.SubstitutionCharacter));
                                    smDisplayBaseIDLabel.Add(ntSub);
                                }
                            }    
                        }

                        smDisplayBaseIDLabel.Add(new XElement(RNAMLTags.RNAMLBasePositionLabel, (ntIdx + 1)));
                        smDisplayPosLabel.Add(new XElement(RNAMLTags.RNAMLBaseCooridinatesLabel, string.Format("{0:N2} {1:N2}", rendering.RenderingMap[ntIdx].StartX, rendering.RenderingMap[ntIdx].StartY)));
                        structuredisplay.Add(smDisplayPosLabel);
                    }
                    structuremodel.Add(structuredisplay);
                }
            }

            molecule.Add(structure);

            XDocument diagramXMLDoc = new XDocument();
            diagramXMLDoc.Add(diagramOutput);
            diagramXMLDoc.Save(targetFile);
        }
    }
}
